from django.utils import timezone
from rest_framework import serializers
from django_redis import get_redis_connection
from decimal import Decimal
from django.db import transaction

from goods.models import SKU
from .models import OrderInfo, OrderGoods


class CartSKUSerializer(serializers.ModelSerializer):
    """购物车商品数据序列化器"""

    count = serializers.IntegerField(label='数量')

    class Meta:
        model = SKU
        fields = ['id', 'name', 'default_image_url', 'price', 'count']


class OrderSettlementSerializer(serializers.Serializer):
    """订单结算数据序列化器"""
    freight = serializers.DecimalField(label='邮费', max_digits=10, decimal_places=2)
    skus = CartSKUSerializer(many=True)


class SaveOrderSerializer(serializers.ModelSerializer):
    """提交订单序列化器"""

    class Meta:
        model = OrderInfo
        fields = ['order_id', 'address', 'pay_method']
        read_only_fields = ('order_id',)
        extra_kwargs = {
            'address': {
                'write_only': True,
                'required': True,
            },
            'pay_method': {
                'write_only': True,
                'required': True
            }
        }

        def create(self, validate_data):
            """重写此方法来保存订单表-->订单商品表"""
            # 获取当前保存订单需要的信息
            user = self.context['request'].user
            # 生成订单编号
            order_id = timezone.now().strftime('%Y%m%d%H%M%S') + '%09d' % user.id
            # 获取validate_data中的address模型对象和怕有_method
            address = validate_data.get('address')
            pay_method = validate_data.get('pay_method')
            status = OrderInfo.ORDER_STATUS_ENUM['UNPAID'] \
                if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] \
                else OrderInfo.ORDER_STATUS_ENUM['UNSEND']

            # 开启一个明显事件
            with transaction.atomic():
                try:
                    # 创建一个事物保存点
                    save_point = transaction.savepoint()
                    # 保存订单基本信息 OrderInfo(一)
                    order = OrderInfo.objects.create(
                        order_id=order_id,
                        user=user,
                        address=address,
                        total_count=0,
                        total_amount=Decimal('0.00'),
                        freight=Decimal('10.00'),
                        pay_method=pay_method,
                        # status='待支付' if '支付宝支付' else '待发货'
                        status=status
                        )
                    # 从redis中获取购物车中被勾选的商品信息
                    redis_conn = get_redis_connection('cart')
                    redis_cart = redis_conn.hgetall('cart_%s' % user.id)
                    cart_selected = redis_conn.smembers('selected_%s' % user.id)

                    # 尽量不要这样一下取出来,可能会有缓存问题
                    # skus = SKU.objects.filter(id__in=cart_selected)
                    # 遍历获取购物车中勾选的商品信息
                    for sku_id in cart_selected:
                        while True:
                            # 获取sku对象
                            sku = SKU.objects.get(id=int(sku_id))
                            sku_count = int(redis_cart[sku_id])
                            # 取出sku库存和销量
                            origin_stock = sku.stock
                            origin_sales = sku.sales
                            # 判断库存
                            if sku_count > origin_stock:
                                raise serializers.ValidationError('库存不足')
                            # 减少库存,增加sku销量
                            # sku.stock -= sku_count
                            # sku.sales += sku_count
                            # sku.save()
                            # 计算新的库存和销量
                            new_stock = origin_stock - sku_count
                            new_sales = origin_sales + sku_count

                            result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                            # 如果result为0,说明用户下单失败,跳过本次while True,继续下一次循环
                            if result == 0:
                                continue
                            # 修改SPU销量
                            spu = sku.goods
                            spu.sales += sku_count
                            spu.save()
                            # 保存订单商品信息
                            OrderGoods.objects.create(
                                order=order,
                                sku=sku,
                                count=sku_count,
                                price=sku.price,
                            )
                            # 改变总价格和总商品数
                            order.total_count += sku_count
                            order.total_amount += sku_count * sku.price

                            # 如果执行到这里,说明下单成功,说明当前sku买到了
                            break
                    # 最后加入邮费,保存订单信息
                    order.total_amount += order.freight
                    order.save()
                # except serializers.ValidationError:
                #     transaction.savepoint_rollback(save_point)
                except Exception:
                    # 暴力回滚
                    transaction.savepoint_rollback(save_point)
                    raise
                else:
                    # 提交事物
                    transaction.savepoint_commit(save_point)
            # 清空购物车中已结算的商品
            # 创建管道
            pl = redis_conn.pipeline()
            pl.hdel('cart_%s' % user.id, *cart_selected)
            pl.srem('selected_%s' % user.id, *cart_selected)
            pl.execute()

            return order



